using System;
using System.Collections;
using System.Data;
using System.IO;
using System.Data.SqlClient;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Text;

using BO = PHSRAG.Insight21.BusinessObjects;
using PHSRAG.Insight21.CDS;
using Utility = PHSRAG.Utility;
using ICachePolicy = PHSRAG.Insight21.Policy.ICachePolicy;
using DataAccess = PHSRAG.Utility.DataAccess;
using Forms=PHSRAG.Insight21.FormsManagement;
using ScriptEngine=PHSRAG.Insight21.ScriptEngine;


namespace PHSRAG.Insight21.Humans
{
	/// <summary>
	/// The protocol process mainly supports the validation and submission of the protocol process.
	/// </summary>
	public class ProtocolProcess : BO.SmartBusinessObject, ICloneable
	{
		#region Statics
		/// <summary>
		/// Key used to place and/or retrieve this object from the cache.
		/// </summary>
		public static string ProtocolProcessKey
		{
			get { return protocolProcessKey; }
		}

		#endregion

		#region instance variables
		private int protocolId;
		private string name;
		private string type;
		private string status;
		private bool locked;
		private int lastLockedVersion;
		private DateTime receivedDate;
		private DateTime approvalDate;
		private DateTime expirationDate;
		private DateTime createDate;
		private DateTime submittedDate;
		private int primaryReviewerId;
		private int secondaryReviewerId;
		private int submitterId;
		private ArrayList protocolVersions;
		private bool validated;
		private DateTime lastModifiedDate;
		private int lastModifiedByUserId;
		private ArrayList studyStaffList;
        private ArrayList nonStudyStaffList;
		private ArrayList protocolDocuments;
		private int rexIRBStatusId;
		private bool showStaff;
		private bool showAttachments;
		private bool beenSubmitted;
		private bool hasBeenLocked;
		private bool resubmission;
        private int movedToRex;
		#endregion

		#region Constants
		private const string protocolProcessKey = "ProtocolProcess_E9C382B9-8191-4504-9F01-93E29601C9F3";
		private const string ProtocolProcessDataTableName = "ProtocolProcess";
		private const string intrinsicProtocolProcessObject = "applicationProtProcess";
		private const string intrinsicProtocolVersionObject = "currentProtVesrion";
		private const string intrinsicCachePolicy = "cachePolicy";
		private const string intrinsicConnectionObject = "connectionString";

		/// <summary>
		///  Protocol Process dataTable Columns
		/// </summary>
		private const string ColumnId = "Id";
		private const string ColumnProtocolId = "ProtocolId";
		private const string ColumnName = "Name";
		private const string ColumnType = "Type";
		private const string ColumnStatus = "Status";
		private const string ColumnLocked = "Locked";
		private const string ColumnLastLockedVersion = "LastLockedVersion";
		private const string ColumnReceivedDate = "ReceivedDate";
		private const string ColumnApprovalDate = "ApprovalDate";
		private const string ColumnExpirationDate = "ExpirationDate";
		private const string ColumnCreateDate = "CreateDate";
		private const string ColumnPrimaryReviewerId = "PrimaryReviewerId";
		private const string ColumnSecondaryReviewerId = "SecondaryReviewerId";
		private const string ColumnSubmitterId = "SubmitterId";
		private const string ColumnLastModifiedDate = "LastModifiedDate";
		private const string ColumnLastModifiedByUserId = "LastModifiedByUserId";
		private const string ColumnSubmittedDate = "SubmittedDate";
		private const string ColumnShowStaff = "ShowStaff";
		private const string ColumnShowAttachments = "ShowAttachments";
		private const string ColumnRexIRBStatusId = "RexIRBStatusId";
		private const string ColumnBeenSubmitted = "BeenSubmitted";
		private const string ColumnHasBeenLocked = "HasBeenLocked";
		private const string ColumnResubmission = "Resubmission";
        private const string ColumnMovedToRex = "MovedToRex";

		#endregion

		#region Properties

		/// <summary>
		/// Determines whether or not to show the Staffing pages.
		/// </summary>
		public bool ShowStaff
		{
			get { return showStaff; }
			set
			{
				SetDirty(ref showStaff, value);
			}
		}

		/// <summary>
		/// Determines whether or not to display the Attachment tab
		/// </summary>
		public bool ShowAttachments
		{
			get { return showAttachments; }
			set
			{
				SetDirty(ref showAttachments, value);
			}
		}

		/// <summary>
		/// Determines whether or not this ProtocolProcess has been 
		/// submitted to WF or not already.
		/// </summary>
		public bool BeenSubmitted
		{
			get { return beenSubmitted; }
			set { SetDirty(ref beenSubmitted, value); }
		}

		/// <summary>
		/// Determines whetehr this PP has been locked at one point or not.
		/// </summary>
		public bool HasBeenLocked
		{
			get { return hasBeenLocked; }
			set { SetDirty(ref hasBeenLocked, value); }
		}

		/// <summary>
		/// Set to true if this process has been resubmitted.
		/// </summary>
		public bool Resubmission
		{
			get { return resubmission; }
			set { SetDirty(ref resubmission, value); }
		}

		/// <summary>
		/// The Id of the Protocol this Process belongs to.
		/// </summary>
		public int ProtocolId
		{
			get { return protocolId; }
			set { SetDirty(ref protocolId, value); }
		}

        /// <summary>
        /// The Id of the Protocol this Process belongs to.
        /// </summary>
        public int MovedToRex
        {
            get { return movedToRex; }
            set { SetDirty(ref movedToRex, value); }
        }

		/// <summary>
		/// Name of the Process.
		/// </summary>
		public string Name
		{
			get { return name; }
			set { SetDirty(ref name, value); }
		}

		/// <summary>
		/// The count of this Process type within the given protocol.
		/// this strips the number off the Name of this process.
		/// </summary>
		public int ProcessCount
		{
			get
			{
				// Initial Reviews don't have a number after them
				if (Name.IndexOf("IR") != -1)
					return 1;
				Regex regEx = new Regex(@"^\D+(?<digits>\d+)$");
				Match match = regEx.Match(Name);
				if (match.Success)
					return Convert.ToInt32(match.Groups["digits"].Value);

				else throw new Exception("No proper Name exists on the Process, Process Number cannot be determined!");
			}
		}

		/// <summary>
		///  The type of the ProtocolPRocess, ex. Amendment, 
		///  Continuing Review, Other event, etc.
		/// </summary>
		public string Type
		{
			get { return type; }
			set { SetDirty(ref type, value); }
		}

		/// <summary>
		/// Status of this ProtocolProcess, ex. Approved
		/// </summary>
		public string Status
		{
			get { return status; }
			set { SetDirty(ref status, value); }
		}

		/// <summary>
		/// Whether or not this protocol process is locked 
		/// 
		/// </summary>
		public bool Locked
		{
			get { return locked; }
			set { SetDirty(ref locked, value); }
		}

		/// <summary>
		/// The last Version# that was locked for the ProtocolProcess.
		/// </summary>
		public int LastLockedVersion
		{
			get { return lastLockedVersion; }
			set { SetDirty(ref lastLockedVersion, value); }
		}

		/// <summary>
		/// Date this protocol Process was received by HRO
		/// </summary>
		public DateTime ReceivedDate
		{
			get { return receivedDate; }
			set { SetDirty(ref receivedDate, value); }
		}

		/// <summary>
		/// Date this Process was approved by the appropriate board(s)
		/// </summary>

		public DateTime ApprovalDate
		{
			get { return approvalDate; }
			set { SetDirty(ref approvalDate, value); }
		}

		/// <summary>
		/// Date this protocol Process expires (APP ONLY?????)
		/// </summary>
		public DateTime ExpirationDate
		{
			get { return expirationDate; }
			set { SetDirty(ref expirationDate, value); }
		}

		/// <summary>
		/// AdmPErsonId of the primary reviewer (within the HRO) of this protocol. 
		/// </summary>
		public int PrimaryReviewerId
		{
			get { return primaryReviewerId; }
			set { SetDirty(ref primaryReviewerId, value); }
		}

		/// <summary>
		/// AdmPErsonId of the secondary reviewer (within the HRO) of this protocol. 
		/// </summary>
		public int SecondaryReviewerId
		{
			get { return secondaryReviewerId; }
			set { SetDirty(ref secondaryReviewerId, value); }
		}

		/// <summary>
		/// FrameWorkUserID of the person who submitted the ProtocolProcess.
		/// </summary>
		public int SubmitterId
		{
			get { return submitterId; }
			set { SetDirty(ref submitterId, value); }
		}

		/// <summary>
		/// Datetime of the last time this Process was saved. Date
		/// setting is handled by the DB engine in the Save PP stored proc.
		/// </summary>
		public DateTime LastModifiedDate
		{
			get { return lastModifiedDate; }
			set { SetDirty(ref lastModifiedDate, value); }
		}

		/// <summary>
		/// FwkDomainUserId of the last person to modify the Protocol Process.
		/// </summary>
		public int LastModifiedByUserId
		{
			get { return lastModifiedByUserId; }
			set { SetDirty(ref lastModifiedByUserId, value); }
		}

		/// <summary>
		/// The Rex IRB Status ID that matches this process in Wrecks.
		/// </summary>
		public int RexIRBStatusId
		{
			get { return rexIRBStatusId; }
			set { SetDirty(ref rexIRBStatusId, value); }
		}

		/// <summary>
		/// status of the Submission.
		/// </summary>
		public bool Validated
		{
			get { return validated; }
			set { SetDirty(ref validated, value); }
		}

		/// <summary>
		/// DateTime the process was submitted to Rex.
		/// </summary>
		public DateTime SubmittedDate
		{
			get { return submittedDate; }
			set { SetDirty(ref submittedDate, value); }
		}

		/// <summary>
		/// Array list of all ProtocolVersions.
		/// </summary>
		public ArrayList ProtocolVersions
		{
			get
			{
				if (protocolVersions == null)
				{ ProtocolVersions = ProtocolVersion.GetVersions(Id, this.CachePolicy); }
				return protocolVersions;
			}
			set { protocolVersions = value; }
		}

		/// <summary>
		/// This property gets the collection of StudyPerson in ArrayList format.
		/// This collection is all staff people associated with the ProtocolProcess.
		/// </summary>
		public virtual ArrayList StudyStaff
		{
			get
			{
				if (studyStaffList == null)
				{
					StudyStaff studyStaff = new StudyStaff(CachePolicy);
					studyStaff.Load(DataAccess.GetConnectionString(), protocolId, Id);
					studyStaffList = studyStaff.GetStudyStaffList();
				}
				return studyStaffList;
			}
			set { studyStaffList = value; }
		}

        /// <summary>
        /// Collection of NonStaffPerson objects in an ArrayList.  It represents users with 
        /// permissions to the protocol, but not staffed to it.
        /// </summary>
        public virtual ArrayList NonStudyStaff
        {
            get
            {
                if (nonStudyStaffList == null)
                {
                    NonStudyStaff nonStudyStaff = new NonStudyStaff(CachePolicy);
                    nonStudyStaff.Load(DataAccess.GetConnectionString(), protocolId, Id);
                    nonStudyStaffList = nonStudyStaff.GetNonStudyStaffList();
                }
                return nonStudyStaffList;
            }
            set { nonStudyStaffList = value; }
        }

		/// <summary>
		/// Determines if there is a PI staffed to the ProtocolProcess
		/// </summary>
		public bool HasPI
		{
			get
			{
				foreach (StaffPerson person in studyStaffList)
				{
					if (person.Role == "Principal Investigator")
						return true;
				}
				return false;
			}
		}

		public string RexTabType
		{
			get
			{
				if (this.Type == Humans.Constants.ProtocolProcessType.Amendment)
					return Humans.Constants.RexIRBStatusType.Amendment;
				else if (this.Type == Humans.Constants.ProtocolProcessType.AdverseEvent)
					return Humans.Constants.RexIRBStatusType.AdverseEvent;
				else if (this.Type == Humans.Constants.ProtocolProcessType.ContinuingReview)
					return Humans.Constants.RexIRBStatusType.ContinuingReview;
				else if (this.Type == Humans.Constants.ProtocolProcessType.OtherEvent)
					return Humans.Constants.RexIRBStatusType.OtherEvent;
				else return Humans.Constants.RexIRBStatusType.InitialReview;
			}
		}

		/// <summary>
		/// Gets or sets the ProtocolDocuments collection associated with the ProtocolProcess
		/// </summary>
		public virtual ArrayList ProtocolDocuments
		{
			get
			{
				if (protocolDocuments == null)
				{
					protocolDocuments = ProtocolDocument.GetProtocolDocuments(protocolId, Id, CachePolicy);
				}
				return protocolDocuments;
			}
			set
			{ protocolDocuments = value; }
		}

		public Protocol Protocol
		{
			get
			{
				if (ProtocolId > 0)
				{
					Protocol protocol = new Protocol(CachePolicy);
					protocol.Load(Utility.DataAccess.GetConnectionString(), ProtocolId);
					return protocol;
				}

				return null;
			}
		}
		#endregion

		#region Constructors
		/// <summary>
		/// ProtocolProcess constructor which takes CachePolicy .
		/// </summary>
		/// <param name="CachePolicy">Current CachePolicy to cache the ProtocolProcess</param>
		public ProtocolProcess(ICachePolicy cachePolicy)
			: base(cachePolicy)
		{
			lastModifiedDate = DateTime.Now;
		}

		/// <summary>
		/// ProtocolProcess constructor which takes CachePolicy and DataRow.
		/// </summary>
		/// <param name="CachePolicy">Current CachePolicy to cache the PP</param>
		/// <param name="row"></param>
		public ProtocolProcess(ICachePolicy cachePolicy, DataRow row)
			: base(cachePolicy)
		{
			PopulateDataMembers(row);
		}
		#endregion

		#region Cloning
		object ICloneable.Clone()
		{
			return Clone(true, true);
		}

		public ProtocolProcess Clone(bool includeStaff, bool includeAttachments)
		{
			ProtocolProcess clone = (ProtocolProcess)MemberwiseClone();
			clone.Id = 0;
			clone.IsClone = true;
			clone.Dirty = true;
            clone.Resubmission = false;

			// Clone the latest protocol version
			clone.protocolVersions = new ArrayList();
			ProtocolVersion clonedVersion = GetLatestProtocolVersion(false, CachePolicy).Clone();
			// Need to set ProtocolProcessId to 0 here, because SaveObject only overwrites the property if it's 0
			clonedVersion.ProtocolProcessId = 0;
			clonedVersion.Version = 1;
			clone.protocolVersions.Add(clonedVersion);

			if (includeStaff)
			{
				clone.studyStaffList = new ArrayList();
				foreach (StaffPerson staffPerson in StudyStaff)
				{
                    if (staffPerson.IsCurrent)
                    {
                        StaffPerson clonedStaffPerson = staffPerson.Clone();
                        clonedStaffPerson.IsClone = true;
                        clone.studyStaffList.Add(clonedStaffPerson);
                    }
				}
			}

			if (includeAttachments)
			{
				clone.protocolDocuments = new ArrayList();
				foreach (ProtocolDocument protocolDocument in ProtocolDocuments)
				{
					// Need to set ProtocolId to 0 here, because SaveObject only overwrites the property if it's 0
					if (protocolDocument.IsCurrent)
					{
                        if (Utility.Settings.GetKeyValue("SaveToSharePoint", false) && protocolDocument.ElectronicFile != null)
                        {
                            protocolDocument.ElectronicFile.IsSharePointDocument = true;
                            protocolDocument.ElectronicFile.FolderHierarchy = ProtocolDocument.CreateFolderHierarchy(this.protocolId.ToString(), protocolDocument.ElectronicFile.Id, protocolDocument.ElectronicFile.Name, false); 
                        }
						ProtocolDocument clonedDocument = protocolDocument.Clone();
						clonedDocument.ProtocolId = 0;
                        clonedDocument.AddedProtocolProcessId = 0;
						clone.protocolDocuments.Add(clonedDocument);
					}
				}
			}

            

			return clone;
		}
		#endregion

		#region Override methods
		/// <summary>
		/// Delete object is not currently implemented. If called, it will throw an error.
		/// </summary>
		/// <param name="sqlTransaction"></param>
		protected override void DeleteObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			try
			{
				Utility.DataAccess.ExecuteNonQuery(sqlTransaction.Connection, sqlTransaction,
					"DeleteProtocolProcess",
					Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, Id));
			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog("ProtocolProcess.DeleteObject: Failed to delete the protocol process", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// Determines if the ProtocolProcess is dirty, based on its own Dirtyness,
		/// and the Dirtyness of it's contained Versions. 
		/// </summary>
		/// <returns></returns>
		public override bool IsDirty()
		{
			if (Dirty)
				return true;
			if (protocolVersions != null)
			{
				int protocolVersionCount = this.protocolVersions.Count;
				for (int i = 0; i < protocolVersionCount; ++i)
				{
					ProtocolVersion version = (ProtocolVersion)this.protocolVersions[i];
					if (version.IsDirty())
						return true;
				}
			}

			if (studyStaffList != null)
			{
				for (int i = 0; i < studyStaffList.Count; ++i)
				{
					if (((StaffPerson)this.studyStaffList[i]).IsDirty())
						return true;
				}
			}

			//ProtocolDocuments
			if (protocolDocuments != null)
			{
				int protocolDocumentCount = protocolDocuments.Count;
				for (int i = 0; i < protocolDocumentCount; ++i)
				{
					ProtocolDocument doc = (ProtocolDocument)protocolDocuments[i];
					if (doc.IsDirty())
						return true;
				}
			}

			return false;
		}


		/// <summary>
		/// Saves the Protocol Process.
		/// </summary>
		/// <param name="sqlTransaction">SQL Transaction to use when saving.</param>
		protected override void SaveObject(System.Data.SqlClient.SqlTransaction sqlTransaction)
		{
			// the stored procedure will determine whether to insert or update an existing Script object.
			object id = DataAccess.ExecuteScalar(sqlTransaction.Connection, sqlTransaction, "SaveProtocolProcess",
					DataAccess.BuildSqlParameterArray(
						"@id", SqlDbType.Int, Id,
						"@protocolId", SqlDbType.Int, ProtocolId,
						"@name", SqlDbType.VarChar, (Name == string.Empty) ? (object)DBNull.Value : (object)Name,
						"@type", SqlDbType.VarChar, Type,
						"@status", SqlDbType.VarChar, (Status == string.Empty) ? (object)DBNull.Value : (object)Status,
						"@locked", SqlDbType.Bit, Locked,
						"@lastLockedVersion", SqlDbType.Int, (LastLockedVersion == 0) ? (object)DBNull.Value : (object)LastLockedVersion,
						"@receivedDate", SqlDbType.DateTime, (ReceivedDate == DateTime.MinValue) ? (object)DBNull.Value : (object)ReceivedDate,
						"@approvalDate", SqlDbType.DateTime, (ApprovalDate == DateTime.MinValue) ? (object)DBNull.Value : (object)ApprovalDate,
						"@expirationDate", SqlDbType.DateTime, (ExpirationDate == DateTime.MinValue) ? (object)DBNull.Value : (object)ExpirationDate,
						"@primaryReviewerId", SqlDbType.Int, (PrimaryReviewerId == 0) ? (object)DBNull.Value : (object)PrimaryReviewerId,
						"@secondaryReviewerId", SqlDbType.Int, (SecondaryReviewerId == 0) ? (object)DBNull.Value : (object)SecondaryReviewerId,
						"@submitterId", SqlDbType.Int, SubmitterId,
						"@lastModifiedUserId", SqlDbType.Int, LastModifiedByUserId,
						"@lastModifiedDate", SqlDbType.DateTime, LastModifiedDate,
						"@submittedDate", SqlDbType.DateTime, (SubmittedDate == DateTime.MinValue) ? (object)DBNull.Value : (object)SubmittedDate,
						"@showStaff", SqlDbType.Bit, ShowStaff,
						"@showAttachments", SqlDbType.Bit, ShowAttachments,
						"@rexIRBStatusId", SqlDbType.Int, RexIRBStatusId,
						"@beenSubmitted", SqlDbType.Bit, BeenSubmitted,
						"@hasBeenLocked", SqlDbType.Bit, HasBeenLocked,
						"@resubmission", SqlDbType.Bit, Resubmission));
			// set the ID to the returned object
			Id = Convert.ToInt32(id);

			if (ProtocolVersions != null)
			{
				int protocolVersionCount = protocolVersions.Count;
				// save its collection(s)...
				for (int i = 0; i < protocolVersionCount; ++i)
				{
					ProtocolVersion version = (ProtocolVersion)protocolVersions[i];
					if (version.ProtocolProcessId == 0)
						version.ProtocolProcessId = Id;
					version.Save(sqlTransaction);
				}
			}

			// Docs
			if (protocolDocuments != null)
			{
				ArrayList deletedPDsList = new ArrayList();
				foreach (ProtocolDocument pd in protocolDocuments)
				{
					if (pd.ProtocolId == 0)
						pd.ProtocolId = ProtocolId;
                    if (pd.AddedProtocolProcessId == 0)
                        pd.AddedProtocolProcessId = Id;
					pd.Save(sqlTransaction);

					if (pd.RemovedProtocolProcessId != 0 || pd.MarkForDeletion)
						deletedPDsList.Add(pd);
				}

				//remove deleted items from items collection
				foreach (ProtocolDocument deletedPD in deletedPDsList)
					protocolDocuments.Remove(deletedPD);
			}

			// Staff
			if (studyStaffList != null)
			{
				// save its collection(s)...
				for (int i = 0, staffCount = studyStaffList.Count; i < staffCount; ++i)
				{
					StaffPerson staff = studyStaffList[i] as StaffPerson;
					if (staff != null)
					{
						if (staff.IsClone)
						{
							staff.ProtocolId = ProtocolId;
							staff.AddedProtocolProcessId = Id;
						}
						staff.Save(sqlTransaction);
					}
				}
			}

		}

		/// <summary>
		/// Load a ProtocolProcess based on the Id.
		/// </summary>
		/// <param name="connectionString">connection to the DB.</param>
		/// <param name="args">ProtocolProcessId</param>
		public override void Load(string connectionString, params object[] args)
		{
			throw new Exception("Don't use ProtocolProcess.Load, uset static factory 'GetProtocolProcess' method instead");
		}

		/// <summary>
		/// Cache this instance using the prevalent cache policy.
		/// </summary>
		public override void Cache()
		{
			CachePolicy.Cache(protocolProcessKey, this);
		}

		/// <summary>
		/// Remove this instance from the cache using the prevalent cache policy.
		/// </summary>
		public override void UnCache()
		{
			CachePolicy.UnCache(protocolProcessKey);
		}

		/// <summary>
		/// use the CacheKey created at the top for caching a PP.
		/// </summary>
		public override string CacheKey()
		{
			return protocolProcessKey;
		}

		/// <summary>
		/// This method returns the required study staff to be displayed
		/// in the View Application (currently a PDF).
		/// </summary>
		/// <returns>ArrayList containing StudyStaff</returns>
		public virtual ArrayList GetStudyStaffForViewApp()
		{
			ArrayList list = new ArrayList();

			foreach (StaffPerson staffPerson in StudyStaff)
			{
				if (Id == staffPerson.AddedProtocolProcessId)
				{
					list.Add(staffPerson);
				}
			}

			return list;
		}

		#endregion

		#region Virtual methods

		/// <summary>
		/// This method returns the required attachments to be displayed
		/// in the View Application (currently a PDF).
		/// </summary>
		/// <returns>ArrayList of ProtocolDocuments</returns>
		public virtual ArrayList GetProtocolDocumentsForViewApp()
		{
			ArrayList list = new ArrayList();

			foreach (ProtocolDocument protocolDocument in ProtocolDocuments)
			{
				if (Id == protocolDocument.AddedProtocolProcessId)
				{
					list.Add(protocolDocument);
				}
			}

			return list;
		}

		/// <summary>
		/// Approves the process. Not implemented directly in the ProtocolProcess,but 
		/// is implemented in all its derived objects.
		/// </summary>
		public virtual void Approve(SqlTransaction insightTransaction, SqlTransaction rexTtransaction,
					string insightConnectionString, string rexConnectionString, Protocol parentProtocol)
		{
			Status = Humans.Constants.ProtocolProcessStatus.Approved;
			ApprovalDate = DateTime.Now;

			/// merge the documents.
			foreach (ProtocolDocument amendDocument in
				ProtocolDocument.GetProtocolDocumentsForApproval(protocolId, Id, CachePolicy))
			{
				if (amendDocument.AddedProtocolProcessId == Id)
				{
					amendDocument.IsCurrent = true;
					amendDocument.Save(insightTransaction);
				}
				if (amendDocument.RemovedProtocolProcessId == Id)
				{
					amendDocument.IsCurrent = false;
					amendDocument.Save(insightTransaction);
				}
			}
		}
		
		//		/// <summary>
		//		/// This method gets the collection of StudyPerson in ArrayList format.
		//		/// This collection is all staff people associated with the ProtocolProcess.
		//		/// </summary>
		//		public virtual ArrayList GetStudyStaff()
		//		{
		//			ArrayList staffPersonList;
		//
		//			if (studyStaff == null)
		//			{
		//				studyStaff = new StudyStaff(CachePolicy);
		//				studyStaff.Load(DataAccess.GetConnectionString(), protocolId, Id);
		//			}
		//			staffPersonList = studyStaff.GetStudyStaffList(); 
		//			return staffPersonList;			
		//		}

		/// <summary>
		/// This method adds StaffPerson object(s). These are the staff people asscociated with the Protocol process.
		/// This method will be implemented in the derived classes.
		/// </summary>
		/// <param name="StaffPerson">StaffPerson Object</param>
		public virtual void AddStudyStaff(StaffPerson staffPerson)
		{
			throw new Exception("ProtocolProcess.AddStudyStaff is not implemented.");
		}
		
		/// <summary>
		/// This method removes the association of StudyStaff object with the Protocol process.
		/// This method will be implemented in the derived classes.
		/// </summary>
		/// <param name="connectionString">connection to the DB.</param>
		/// <param name="StaffPerson">StaffPerson Object</param>
		public virtual void RemoveStudyStaff(string connectionString, StaffPerson staffPerson)
		{
			throw new Exception("ProtocolProcess.RemoveStudyStaff is not implemented.");
		}
		
		/// <summary>
		/// /// This method submits the process to Rex. This is called when a process has been validated 
		/// (passed all validations) and is ready to be submitted to Rex. Depending on the process type,
		/// different actions happen here. EX. the Initial Review will insert the Protocol and return a 
		/// Protocol Number from Rex, whereas an OtherEvent may only add that Process to the Protocol.
		/// </summary>
		/// <param name="CachePolicy">a passed-in CachePolicy</param>
		/// <param name="insightConnectionString">the insight Database's connection string</param>
		/// <param name="rexConnectionString">the REx Database's connection string</param>
		public virtual void Submit(ICachePolicy cachePolicy, string insightConnectionString, string rexConnectionString, string executingAssemblyPath, RexParams rexParameters, bool IsRelocked)
		{
			if (rexParameters == null)
				rexParameters = new RexParams();

			Protocol currProtocol = new Protocol(cachePolicy);
			currProtocol.Load(insightConnectionString, this.ProtocolId);

			// get all the intrinsics and run teh Submission script here. 
			// Also, add in the rest of the Rex fields, checking with Irina 
			// for any new stored procedure changes.  
			#region Runscript
			String submissionScriptType;
			if (currProtocol.ModuleType == Humans.Constants.ModuleType.Humans)
			{
				submissionScriptType = (string)ScriptEngine.Constants.ScriptType.HumansSubmission;
				SubmitHumansProcess(cachePolicy,
									insightConnectionString,
									rexConnectionString,
									executingAssemblyPath,
									rexParameters,
									submissionScriptType,
									currProtocol,
									IsRelocked);
			}
			else
			{
				switch (this.Type)
				{
					case Constants.AnimalProtocolProcessType.InitialReview:
						submissionScriptType = (string)ScriptEngine.Constants.ScriptType.AnimalSubmissionInitialReveiew;
						break;
					case Constants.AnimalProtocolProcessType.Amendment:
						submissionScriptType = (string)ScriptEngine.Constants.ScriptType.AnimalSubmissionAmendment;
						break;
					case Constants.AnimalProtocolProcessType.AnnualReview:
						submissionScriptType = (string)ScriptEngine.Constants.ScriptType.AnimalSubmissionAnnualReveiew;
						break;
					case Constants.AnimalProtocolProcessType.Deficiency:
						submissionScriptType = (string)ScriptEngine.Constants.ScriptType.AnimalSubmissionDeficiency;
						break;
					case Constants.AnimalProtocolProcessType.TriennialReview:
						submissionScriptType = (string)ScriptEngine.Constants.ScriptType.AnimalSubmissionTriennialReveiew;
						break;
					default:
						throw new Exception("unknown type of process: " + this.Type);
				}

				SubmitAnimalsProcess(cachePolicy,
								insightConnectionString,
								rexConnectionString,
								executingAssemblyPath,
								rexParameters,
								submissionScriptType,
								currProtocol,
								IsRelocked);
			}
			#endregion
			Lock(insightConnectionString, cachePolicy, null);

            // Now set the flag for the process that it has been submitted to Rex.
            Utility.DataAccess.ExecuteNonQuery(insightConnectionString,
                "UpdateMoveToRexSatusForProcess",
                Utility.DataAccess.BuildSqlParameterArray(
                "@processId", SqlDbType.Int, Id));
		}

		/// <summary>
		/// Updates staff changes in REX.  The PI is not updated
		/// </summary>
		/// <param name="insightConnectionString">string containing
		/// info to connect to Insight db</param>
		/// <param name="rexConnectionString">string containing
		/// info to connect to REX db</param>
		public virtual void UpdateStaffInREX(string insightConnectionString,
			string rexConnectionString, Protocol protocol)
		{
			SqlConnection rexConn = new SqlConnection(rexConnectionString);
			SqlTransaction rexTransaction = null;
			try
			{
				int rexProtocolId = protocol.RexProtocolId;

				rexConn.Open();
				rexTransaction = rexConn.BeginTransaction();

				// Rex removes the staff to do its updates, so remove the staff first, then re-add them all.
				Utility.DataAccess.ExecuteNonQuery(rexTransaction.Connection, rexTransaction,
					"spIRBStudyStaffDelete",
					Utility.DataAccess.BuildSqlParameterArray(
					"@nIRBProtocolID", SqlDbType.Int, rexProtocolId));
				// now move the study staff over to Rex, if they're not already there.
				for (int i = 0, count = StudyStaff.Count; i < count; ++i)
				{
					StaffPerson staff = (StaffPerson)StudyStaff[i];
					// don't move over the PI.
					if (staff.RoleId !=
						Humans.Constants.StaffRoleType.PrincipalInvestigator)
					{
						if (staff.Person.RexRecomId == 0)
						{
							staff.Person.CreateRecomRecord(insightConnectionString,
								rexConnectionString);
						}
						// todo: remove this local var
						int rexStudyStaffId =
							Convert.ToInt32(Utility.DataAccess.ExecuteScalar(
							rexTransaction.Connection,
							rexTransaction,
							"spIRBStudyStaffUpdate",
							Utility.DataAccess.BuildSqlParameterArray(
							"@nIRBProtocolId", SqlDbType.Int, rexProtocolId,
							"@nRecomAbstractID", SqlDbType.Int, staff.Person.RexRecomId,
							"@sName", SqlDbType.VarChar, string.Empty, // not used, but Rex needs it...
							"@sPosition", SqlDbType.VarChar, staff.RexRoleName,
							"@bGetsMail", SqlDbType.Bit, staff.IsContactPerson,
                            "@sEmailAddress", SqlDbType.VarChar, staff.Person.Email
                            )));
					}
					else
						// Update the Protocol record with the PI
						UpdatePIInREX(insightConnectionString, rexConnectionString,
							protocol, rexTransaction, staff.Person.RexRecomId);
				}               

                for (int i = 0, count = NonStudyStaff.Count; i < count; ++i)
                {
                    NonStaffPerson nonStaff = (NonStaffPerson)NonStudyStaff[i];

                    if (nonStaff.IsContactPerson)
                    {
                        if (nonStaff.Person.RexRecomId == 0)
                        {
                            nonStaff.Person.CreateRecomRecord(insightConnectionString,
                                rexConnectionString);
                        }                        
                        int rexStudyStaffId =
                            Convert.ToInt32(Utility.DataAccess.ExecuteScalar(
                            rexTransaction.Connection,
                            rexTransaction,
                            "spIRBStudyStaffUpdate",
                            Utility.DataAccess.BuildSqlParameterArray(
                            "@nIRBProtocolId", SqlDbType.Int, rexProtocolId,
                            "@nRecomAbstractID", SqlDbType.Int, nonStaff.Person.RexRecomId,
                            "@sName", SqlDbType.VarChar, string.Empty, // not used, but Rex needs it...
                            "@sPosition", SqlDbType.VarChar, "M-Gets Mail",
                            "@bGetsMail", SqlDbType.Bit, nonStaff.IsContactPerson,
                            "@sEmailAddress", SqlDbType.VarChar, nonStaff.Person.Email
                            )));
                    }
                }               

				rexTransaction.Commit();
			}
			catch (Exception ex)
			{
				rexTransaction.Rollback();
				throw new Exception("Staff Updates in REX failed", ex);
			}
			finally
			{
				if (rexConn.State != ConnectionState.Closed)
					rexConn.Close();
			}
		}
		
		/// <summary>
		/// Adds a new protocol document to the ProtocolDocuments collection
		/// </summary>
		/// <param name="protocolId">Protocol Id</param>
		/// <param name="title">Title of the attachment</param>
		/// <param name="type">Type of the attachment</param>
		/// <param name="isHardCopy">Indicates whether or not the attachment is a hardcopy or not</param>
		/// <param name="protocolProcessId">Protocol Process Id</param>
		/// <returns>The new ProtocolDocument object added to the container</returns>
		public virtual ProtocolDocument AddProtocolDocument(int protocolId, string title, string type, string refMeaning, bool isHardCopy, int protocolProcessId)
		{
			ProtocolDocument newAttachmentType = new ProtocolDocument(CachePolicy);
			newAttachmentType.Id = 0;
			newAttachmentType.ProtocolId = protocolId;
			newAttachmentType.Type = type;
			newAttachmentType.RefMeaning = refMeaning;
			newAttachmentType.Name = title;
			newAttachmentType.IsHardCopy = isHardCopy;
			newAttachmentType.AddedProtocolProcessId = protocolProcessId;
			newAttachmentType.LastLockedVersion = LastLockedVersion;
			newAttachmentType.ProcessName = Name;            
			ProtocolDocuments.Add(newAttachmentType);
			this.ShowAttachments = true;

			return newAttachmentType;
		}

        /// <summary>
        /// Adds a new protocol document to the ProtocolDocuments collection
        /// </summary>
        /// <param name="protocolId">Protocol Id</param>
        /// <param name="title">Title of the attachment</param>
        /// <param name="type">Type of the attachment</param>
        /// <param name="isHardCopy">Indicates whether or not the attachment is a hardcopy or not</param>
        /// <param name="protocolProcessId">Protocol Process Id</param>
        /// <returns>The new ProtocolDocument object added to the container</returns>
        public virtual ProtocolDocument AddProtocolDocument(int protocolId, string title, string type, string refMeaning, bool isHardCopy, int protocolProcessId, int parentDocumentId)
        {
            ProtocolDocument newAttachmentType = new ProtocolDocument(CachePolicy);
            newAttachmentType.Id = 0;
            newAttachmentType.ProtocolId = protocolId;
            newAttachmentType.Type = type;
            newAttachmentType.RefMeaning = refMeaning;
            newAttachmentType.Name = title;
            newAttachmentType.IsHardCopy = isHardCopy;
            newAttachmentType.AddedProtocolProcessId = protocolProcessId;
            newAttachmentType.LastLockedVersion = LastLockedVersion;
            newAttachmentType.ProcessName = Name;
            newAttachmentType.ParentDocumentId = parentDocumentId;
            ProtocolDocuments.Add(newAttachmentType);
            this.ShowAttachments = true;

            return newAttachmentType;
        }
		
		/// <summary>
		/// Executes the submission script
		/// </summary>
		/// <returns>RexParams object</returns>
		public virtual RexParams ExecuteSubmissionScript()
		{
			//Submission script
			try
			{
				ScriptEngine.Script submissionScript = null;
				ArrayList scripts = ScriptEngine.Script.GetScriptsByType(FormsManagement.Constants.ScriptType.Submission, CachePolicy);
				if (scripts.Count > 0)
				{
					submissionScript = (ScriptEngine.Script)scripts[0];
				}


				using (ScriptEngine.ScriptEngineHost scriptHost =
				   new PHSRAG.Insight21.ScriptEngine.ScriptEngineHost("SubmissionScript://Scripting/", "SubmissionScript", true))
				{

					ArrayList refs = ScriptEngine.ScriptReference.GetAllScriptReferences(Utility.DataAccess.GetConnectionString());
					for (int i = 0; i < refs.Count; ++i)
					{
						ScriptEngine.ScriptReference reference = (ScriptEngine.ScriptReference)refs[i];
						scriptHost.AddDLLReference(reference.Path);
					}

					scriptHost.AddIntrinsicObject("connectionString", Utility.DataAccess.GetConnectionString());
					scriptHost.AddIntrinsicObject("cachePolicy", CachePolicy);
					scriptHost.AddIntrinsicObject("intrinsicProtocolProcess", this);

					ProtocolVersion currentVersion = GetLatestProtocolVersion(false, CachePolicy) as ProtocolVersion;
					if (currentVersion == null)
					{
						throw new Exception("No protocol version found");
					}
					scriptHost.AddIntrinsicObject("intrinsicProtocolVersion", currentVersion);

					RexParams rexParams = new RexParams();
					scriptHost.AddIntrinsicObject("rexParams", rexParams);


					if (scriptHost.Compile(submissionScript))
						scriptHost.RunScript(submissionScript, "SubmissionScript.Script", "Main");

					return rexParams;
				}
			}
			catch (Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed to execute Submission Script", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// 
		/// </summary>
		public virtual Humans.RexParams RunApprovalScript()
		{
			Humans.RexParams rexParameters = new RexParams();
            if (this.Protocol.ModuleType == Constants.ModuleType.Animals)
                rexParameters = new AnimalsRexParams();

			ArrayList scripts = ScriptEngine.Script.GetScriptsByType(Utility.DataAccess.GetConnectionString(),
			   (string)ScriptEngine.Constants.ScriptType.Approval, CachePolicy);

			// grab the directory info for use in both scripting places.
			DirectoryInfo directoryInfo = new DirectoryInfo(System.IO.Path.GetDirectoryName(
			   (new Regex(@"^file:/+")).Replace(Assembly.GetExecutingAssembly().CodeBase, string.Empty)));

			ScriptEngine.Script approvalScript = null;

			if (scripts.Count > 0)
				approvalScript = (ScriptEngine.Script)scripts[0];

			if (approvalScript != null)
			{
				using (ScriptEngine.ScriptEngineHost scriptHost =
				   new PHSRAG.Insight21.ScriptEngine.ScriptEngineHost(
					  ScriptEngine.Constants.RootMoniker.ApprovalScriptMoniker,
					  ScriptEngine.Constants.RootNamespaces.ApprovalScript,
					  true))
				{
					ArrayList refs = ScriptEngine.ScriptReference.GetAllScriptReferences(
					   Utility.DataAccess.GetConnectionString());

					for (int i = 0; i < refs.Count; ++i)
					{
						ScriptEngine.ScriptReference reference = (ScriptEngine.ScriptReference)refs[i];
						scriptHost.AddDLLReference(string.Format("{0}\\{1}", directoryInfo.FullName, reference.Name));
					}

					// add the connection string
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ConnectionString,
					   Utility.DataAccess.GetConnectionString());

					// add the Process
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolProcss,
					   this);

					ProtocolVersion currentVersion = GetLatestProtocolVersion(Utility.DataAccess.GetConnectionString(),
					   false, CachePolicy) as ProtocolVersion;

					if (currentVersion == null)
					{
						throw new Exception("No protocol version found");
					}
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolVersion, currentVersion);

					// add the RexParams
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.RexParams, rexParameters);

					// add the caching policy
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.CachePolicy, CachePolicy);

					// compile and run the script.
					if (scriptHost.Compile(approvalScript))
						scriptHost.RunScript(approvalScript,
						   ScriptEngine.Constants.AssemblyType.ApprovalScript,
						   ScriptEngine.Constants.MethodsToRun.Main);
				}
			}

			return rexParameters;
		}

		#endregion

		#region Public Methods
        /// <summary>
        /// Returns a list of users with at least the minimum access right bit permission specified
        /// </summary>
        /// <param name="minPermission">Access right bit of minimum required permission</param>
        /// <returns></returns>
        public ArrayList GetUsersWithMinimumPermission(int minPermission)
        {
            ArrayList list = new ArrayList();

            foreach (BaseStudyPerson person in StudyStaff)
            {
                if (person.UserId > 0)
                {
                    if (!list.Contains(person) && person.PermissionLevel >= minPermission)
                    {
                        list.Add(person);
                    }
                }
            }

            foreach (BaseStudyPerson person in NonStudyStaff)
            {
                if (person.UserId > 0)
                {
                    if (!list.Contains(person) && person.PermissionLevel >= minPermission)
                    {
                        list.Add(person);
                    }
                }
            }
            return list;
        }

		/// <summary>
		/// This inserts a record into the PendingApplications_Fct table since it doesn't contain
		/// submissions that haven't made it to REX and back yet.
		/// </summary>
		public void InsertIntoPendingFactTable(string connectionString)
		{
			Protocol protocol = new Protocol(CachePolicy);
			protocol.Load(connectionString, protocolId);

			SqlParameter[] args = DataAccess.BuildSqlParameterArray("@protocolId", SqlDbType.Int, protocolId,
				"@formsID", SqlDbType.VarChar, name,
				"@title", SqlDbType.VarChar, protocol.Title,
				"@overallStatus", SqlDbType.VarChar, protocol.OverallStatus,
				"@isLocked", SqlDbType.Bit, locked,
				"@fwkResourceId", SqlDbType.Int, protocol.FwkResourceId);

			string sponsor = protocol.SponsorName;
			if (sponsor != string.Empty)
				DataAccess.AppendToSqlParameterArray(ref args, "@sponsorName", SqlDbType.VarChar, sponsor);

			string protocolNumber = protocol.ProtocolNumber;
			if (protocolNumber != string.Empty)
				DataAccess.AppendToSqlParameterArray(ref args, "@protocolNumber", SqlDbType.VarChar, protocolNumber);

			string piName = protocol.PIName;
			if (piName != string.Empty)
				DataAccess.AppendToSqlParameterArray(ref args, "@piName", SqlDbType.VarChar, piName);

			if (submittedDate != DateTime.MinValue)
				DataAccess.AppendToSqlParameterArray(ref args, "@submissionDate", SqlDbType.DateTime, submittedDate);

			int organizationId = protocol.OrganizationId;
			if (organizationId > 0)
				DataAccess.AppendToSqlParameterArray(ref args, "@organizationId", SqlDbType.Int, organizationId);

			int piPersonId = protocol.PIPersonId;
			if (piPersonId > 0)
				DataAccess.AppendToSqlParameterArray(ref args, "@piPersonId", SqlDbType.Int, piPersonId);

			if (expirationDate > DateTime.MinValue)
				DataAccess.AppendToSqlParameterArray(ref args, "@expirationDate", SqlDbType.DateTime, expirationDate);

			string version = protocol.Version;
			if (version != string.Empty)
				DataAccess.AppendToSqlParameterArray(ref args, "@version", SqlDbType.VarChar, version);

			if (Id > 0)
				DataAccess.AppendToSqlParameterArray(ref args, "@protocolProcessId", SqlDbType.Int, Id);

			DataAccess.ExecuteNonQuery(connectionString, "InsertPendingApplications_Fct", args);
		}


		/// <summary>
		/// Returns the requested Version of the ProtocolPRocess.
		/// </summary>
		/// <param name="protocolVersion">Version # of the proces</param>
		/// <returns>returns the appropriate Version object, otherwise will return a NULL one if
		/// the requested version doesn't exist.</returns>
		public ProtocolVersion GetVersion(int protocolVersion)
		{
			return new ProtocolVersion(CachePolicy);
		}


		/// <summary>
		/// Unlocks the ProtocolProcess for editing. Note that the Unlock method
		/// will save the ProtocolProcess and Protocol changes to the database.
		/// <param name="connectionString">database connection string</param>
		/// <param name="CachePolicy">prevalent cachepolicy</param>
		/// <param name="parentProtocol">Optional parent protocol object, used in 
		/// derived behavior  (see Application.cs)</param>
		public virtual void Unlock(string connectionString, ICachePolicy cachePolicy, Protocol parentProtocol)
		{
			if (Locked)
			{
				Locked = false;
				Save(connectionString);
			}
		}


		/// <summary>
		/// Locks the protocolProcess, preventing it from
		///  being edited. Note that the Lock method
		/// will save the ProtocolProcess and Protocol changes to the database.
		/// </summary>
		/// <param name="connectionString">database connection string</param>
		/// <param name="CachePolicy">prevalent cachepolicy</param>
		/// <param name="parentProtocol">Optional parent protocol object, used in 
		/// derived behavior (see Application.cs)</param>
		public virtual void Lock(string connectionString, ICachePolicy cachePolicy, Protocol parentProtocol)
		{
			Locked = true;
			HasBeenLocked = true;
			ProtocolVersion latestVersion = GetLatestProtocolVersion(false, cachePolicy);

			if (this.ProtocolVersions.Count > 0 && latestVersion == null)
				latestVersion = (ProtocolVersion)this.ProtocolVersions[0];

			if (latestVersion != null)
			{
				LastLockedVersion = latestVersion.Version;
				latestVersion.Status = this.Status;
				latestVersion.LockDate = DateTime.Now;
			}

			SqlConnection connection = new SqlConnection(connectionString);

			// create a connection and open it.
			connection.Open();

			// create a transaction on the connection to be passed around.
			SqlTransaction transaction = connection.BeginTransaction(Assembly.GetExecutingAssembly().GetName().Name);

			try
			{
				Save(transaction);
				if (latestVersion != null)
					latestVersion.Save(transaction);

				// commit the SQL transaction.
				transaction.Commit();
			}
			catch
			{
				// rollback the transaction if it exists.
				if (transaction != null)
				{
					transaction.Rollback();
				}
				throw;
			}
			finally
			{

				// do some cleanup.
				if (connection.State != ConnectionState.Closed)
					connection.Close();
			}

		}


		/// <summary>
		///  Create and add a new ProtocolVersion to this process 
		///  version collection,
		///  set some defaults,and return it.
		/// </summary>
		/// <param name="CachePolicy">CachePolicy to create the version with.</param>
		/// <returns>ProtocolVersion</returns>
		public ProtocolVersion AddNewVersion(ICachePolicy cachePolicy)
		{
			ProtocolVersion newVersion = new ProtocolVersion(cachePolicy);
			newVersion.ProtocolProcessId = Id;
			// set to WIP
			newVersion.Status = "PVSTATUS_WIP";
			ProtocolVersions.Add(newVersion);
			return newVersion;
		}


		/// <summary>
		///  Validate the protocol application and return the LogItems as applicable.
		///  Method trace as follows:
		///  Remove log items attached with the Protocol Process Id.
		///  Get the latest unlocked protocol version by making a call to GetLatestProtocolVersion passing in "false" for the boolean parameter
		///  Get the Questionnaire answers assosiated with the protocol version.
		///  Iterate through questionnaire answers to get the QuestionnaireItems
		///  Iterate through the questionnaire Items to verify the presence of the required answers 
		///  Iterate throught thechild items to verify the presence of answers 
		///	Get the validation script assosiated with the Questionnaire version.
		///	Set the required intrinsic .
		///	Run the validation script.
		///	If LogItems.count=0, Set Validated =true
		/// </summary>
		/// <param name="CachePolicy">CachePolicy .</param>
		/// <returns>ArrayList(Array of LogItem objects)</returns>
		public ArrayList ValidateSubmission(ICachePolicy policy)
		{
			throw new Exception("Don't call this method on the object!");
		}


		/// <summary>
		/// This method checks if the organization is of the type 'Department' or 'Unit' and returns the count =1 if true else count=0
		/// </summary>
		/// <returns></returns>
		public int GetValidOrgCount()
		{
			try
			{
				object OrgCount = (Utility.DataAccess.GetDataTable(Utility.DataAccess.GetConnectionString(), "CheckOrgDomainType", Utility.DataAccess.BuildSqlParameterArray("@protocolId", SqlDbType.Int, ProtocolId))).Rows.Count;
				return Convert.ToInt32(OrgCount);
			}
			catch (Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed to get valid organization count ,error occurred at GetValidOrgCount()", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// GetLatestHumansRexProcessData selects a number of information from the tblIRBStatus
		/// in Rex, teh table where 'Processes' are stored (ex. AMEs, CRs, IRs, etc.). When calling 
		/// Submit, if this has already been moved over to Rex, we need to get the latest / top attachmentTitle
		/// ID of the IRBStatus record we're updating. See TrackIt 7869 for more information.
		/// </summary>
		/// <param name="protocolNumber">protocolnumber to lookup</param>
		/// <param name="rexTransaction">the Rex DB Transaction</param>
		/// <param name="rexProcessType">the process type (sTabType) for Rex to lookup</param>
		/// <returns></returns>
		public DataSet GetLatestHumansRexProcessData(string protocolNumber,
													 SqlTransaction rexTransaction,
													 string rexProcessType)
		{
			return Utility.DataAccess.GetDataSet(
				rexTransaction.Connection,
				rexTransaction,
				"GetHumansStatusIDForProcess",
				Utility.DataAccess.BuildSqlParameterArray("@protocolNumber", SqlDbType.VarChar, protocolNumber,
									"@processId", SqlDbType.Int, this.Id,
									"@processType", SqlDbType.VarChar, rexProcessType));
		}

		/// <summary>
		/// GetLatestAnimalsRexProcessData selects a number of information from the different Animals process
		/// itablesn Rex (ex. AMEs, CRs, IRs, etc.). When calling the
		/// Submit, if this has already been moved over to Rex, we need to get the latest / top attachmentTitle
		/// ID of the corresponding Rex record we're updating. See TrackIt 7869 for more information.
		/// </summary>
		/// <param name="protocolNumber"></param>
		/// <param name="rexTransaction"></param>
		/// <returns></returns>
		public DataSet GetLatestAnimalsRexProcessData(string protocolNumber, SqlTransaction rexTransaction)
		{
			return Utility.DataAccess.GetDataSet(
				rexTransaction.Connection,
				rexTransaction,
				"GetAnimalsStatusIDForProcess",
				Utility.DataAccess.BuildSqlParameterArray("@protocolNumber", SqlDbType.VarChar, protocolNumber,
									"@processId", SqlDbType.Int, this.Id,
									"@processType", SqlDbType.VarChar, this.Type));
		}


		/// <summary>
		/// If a QuestionnaireVersion's QuestionDocument is marked as required, check if it needs 
		/// to be attached(based on the question and answer associated with the document). 
		/// If so, check if it is listed in the required attachments for the protocol.
		/// If not, add it to the list of the required attachments.
		/// </summary>
		/// <param name="questAnswer">QuestionnaireAnswer object</param>
		public void VerifyRequiredAttachments(FormsManagement.QuestionnaireAnswer questAnswer, CDS.RefCodes refCodes, ProtocolVersion protocolVersion)
		{
			FormsManagement.QuestionnaireVersion version = questAnswer.QuestionnaireVersion;
			ArrayList similarQAs = protocolVersion.GetAllQVQAs(version.Id);
			foreach (FormsManagement.QuestionDocument questionDocument in version.Documents)
			{
				int supposedPDCountForQDType = 0;
				int actualPDCountForQDType = 0;
				if (questionDocument.IsRequired)
				{
					bool isMultiInputOrMultiSelect = false;
					foreach (FormsManagement.QuestionnaireItem item in version.Items)
					{
						if (item.Name == questionDocument.ItemName)
						{
							if (item.Type == FormsManagement.QuestionnaireItem.MultiSelectItemType 
								|| item.Type == FormsManagement.QuestionnaireItem.DropDownMultiSelectItemType
								|| item.Type == FormsManagement.QuestionnaireItem.CustomValueSelectorItemType)
							{
								isMultiInputOrMultiSelect = true;
							}
							break;
						}
					}

					//for multiinput or multiselect control questions, add the attachments with titles set to the values of the answers provided
					//otherwise generate a new unique title
					if (!isMultiInputOrMultiSelect)
					{
						foreach (FormsManagement.QuestionnaireAnswer qA in similarQAs)
						{
							foreach (FormsManagement.Answer answer in qA.GetAnswers(questionDocument.ItemName))
							{
								if (answer.Value == questionDocument.ItemValue)
								{
									supposedPDCountForQDType += 1;
									break;
								}
							}
						}
					}
					else
					{
						foreach (FormsManagement.QuestionnaireAnswer qA in similarQAs)
						{
							supposedPDCountForQDType = supposedPDCountForQDType + qA.GetAnswers(questionDocument.ItemName).Count;
						}
					}

					//Get the attached documents from the protocol document.
					foreach (Humans.ProtocolDocument pD in ProtocolDocuments)
					{
						//If the user has opted to send the hard copy of the document,No Log Item should be logged.
						if ((questionDocument.Type == pD.Type))
							actualPDCountForQDType += 1;
					}

					if (supposedPDCountForQDType > actualPDCountForQDType)
					{
						string attachmentTypeName = refCodes.GetRefCode(questionDocument.Type).Meaning;
						if (!isMultiInputOrMultiSelect)
						{
							//for multiinput or multiselect control questions, add the attachments with titles set to the values of the answers provided
							//otherwise generate a new unique title
							AddProtocolDocument(ProtocolId,
								ProtocolDocument.GetNewTitleForType(CachePolicy, ProtocolId, attachmentTypeName, questionDocument.Type),
								questionDocument.Type, attachmentTypeName, false, Id);
						}
						else
						{
							foreach (FormsManagement.Answer answer in questAnswer.GetAnswers(questionDocument.ItemName))
							{
								bool isDocumentAttached = false;
								foreach (Humans.ProtocolDocument pD in ProtocolDocuments)
								{
									if (pD.Type == questionDocument.Type && pD.Name == answer.Value)
									{
										isDocumentAttached = true;
										break;
									}
								}
								if (!isDocumentAttached)
								{
									//for multiinput or multiselect control questions, add the attachments with titles set to the values of the answers provided
									//otherwise generate a new unique title
									AddProtocolDocument(ProtocolId,
										answer.Value,
										questionDocument.Type, attachmentTypeName, false, Id);
								}
							}
						}
					}
				}
			}
		}
		#endregion

		#region Private Methods
		/// <summary>
		/// Broken-out method called within Submit, only if the Parent protocol's module type is Animals
		/// </summary>
		/// <param name="cachePolicy">cache policy</param>
		/// <param name="insightConnectionString">insight conn string</param>
		/// <param name="rexConnectionString">rex conn string</param>
		/// <param name="executingAssemblyPath">local executing path</param>
		/// <param name="rexParameters">RexParams object instance</param>
		/// <param name="submissionScriptType">type of the Submission</param>
		/// <param name="currProtocol">the current protocol- this processes' parent</param>
		/// <param name="IsRelocked">flag passed into Submit, passed thru here</param>
		private void SubmitAnimalsProcess(ICachePolicy cachePolicy, string insightConnectionString, string rexConnectionString,
					string executingAssemblyPath, RexParams rexParameters, string submissionScriptType, Protocol currProtocol, bool IsRelocked)
		{
			currProtocol.RexProtocolId = GetCurrentRexProtocolId(rexConnectionString, null, currProtocol.ProtocolNumber, Constants.ModuleType.Animals);
			currProtocol.Save(insightConnectionString);

			int rexProtId = currProtocol.RexProtocolId;

            /*************************************************/
            //Get the submission script from the active verion.
            ProtocolVersion pv = GetLatestProtocolVersion(false,cachePolicy);
            ArrayList qAs = pv.GetQuestionnaireAnswers(cachePolicy);
            FormsManagement.QuestionnaireVersion questionnaireVersion = null;
            
            foreach (FormsManagement.QuestionnaireAnswer qA in qAs)
            {
                if (this.Type == Humans.Constants.AnimalProtocolProcessType.Amendment && qA.Name.ToLower() == "iacucamendment")
				{
					questionnaireVersion = qA.QuestionnaireVersion;
                    submissionScriptType = FormsManagement.Constants.AnimalsSubmissionScriptType.Amendment;
                    break;
				}
                else if (this.Type == Humans.Constants.AnimalProtocolProcessType.Deficiency)
                {
                    questionnaireVersion = qA.QuestionnaireVersion;
                    submissionScriptType = FormsManagement.Constants.AnimalsSubmissionScriptType.Deficiency;
                    break;
                }
				else if (this.Type == Humans.Constants.AnimalProtocolProcessType.AnnualReview && 
                    qA.QuestionnaireCategory == FormsManagement.Constants.AnimalsFormCatgory.AnnualReview)
				{
					questionnaireVersion = qA.QuestionnaireVersion;
                    submissionScriptType = FormsManagement.Constants.AnimalsSubmissionScriptType.AnnualReview;
                    break;
				}
				else if (this.Type == Humans.Constants.AnimalProtocolProcessType.TriennialReview &&
                    qA.QuestionnaireCategory == FormsManagement.Constants.AnimalsFormCatgory.TriennialReview)
				{
					questionnaireVersion = qA.QuestionnaireVersion;
                    submissionScriptType = FormsManagement.Constants.AnimalsSubmissionScriptType.TriennialReview;
                    break;
				}
                else if (this.Type == Humans.Constants.AnimalProtocolProcessType.InitialReview &&
                    qA.QuestionnaireCategory == FormsManagement.Constants.AnimalsFormCatgory.InitialApplication)
                {
                    questionnaireVersion = qA.QuestionnaireVersion;
                    submissionScriptType = FormsManagement.Constants.AnimalsSubmissionScriptType.Initial;
                    break;
                }	
            }
								

            if (null == questionnaireVersion || submissionScriptType == string.Empty)
            {
                throw new Exception("Questionnaire version or Submission script type cannot be null");
            }
		    ScriptEngine.Script submissionScript =
                (ScriptEngine.Script)questionnaireVersion.Scripts[submissionScriptType];
                       

			if (submissionScript != null && submissionScript.ScriptText != null)
			{
				using (ScriptEngine.ScriptEngineHost scriptHost =
				   new PHSRAG.Insight21.ScriptEngine.ScriptEngineHost(
						 ScriptEngine.Constants.RootMoniker.SubmissionScriptMoniker,
						 ScriptEngine.Constants.RootNamespaces.SubmissionScript,
						 true))
				{
					ArrayList refs = ScriptEngine.ScriptReference.GetAllScriptReferences(
					   insightConnectionString);

					for (int i = 0; i < refs.Count; ++i)
					{
						ScriptEngine.ScriptReference reference = (ScriptEngine.ScriptReference)refs[i];
						scriptHost.AddDLLReference(string.Format("{0}\\{1}", executingAssemblyPath, reference.Name));
					}

					// add the connection string
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ConnectionString,
					   insightConnectionString);

					// add the Process
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolProcss,
					   this);

					ProtocolVersion currentVersion = GetLatestProtocolVersion(insightConnectionString,
					   false, cachePolicy) as ProtocolVersion;
					if (currentVersion == null)
					{
						throw new Exception("No protocol version found");
					}
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolVersion, currentVersion);


					// add the RexParams
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.RexParams, rexParameters);

					// add the caching policy
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.CachePolicy, cachePolicy);

					// compile and run the script.
					if (scriptHost.Compile(submissionScript))
						scriptHost.RunScript(submissionScript,
						   ScriptEngine.Constants.AssemblyType.SubmissionScript,
						   ScriptEngine.Constants.MethodsToRun.Main);
				}
			}

			// Go get the correct protocol process number (ex. AME2) here, immediately before moving it over to Rex.
			if (this.Type != ProtocolProcessType.AnimalsApplication.ToString() && !IsRelocked && this.Name.Contains("InProg"))
			{
				string typeRefCode = string.Empty;
				string processName = string.Empty;

				if (this.Type == Humans.Constants.AnimalProtocolProcessType.Amendment)
				{
					typeRefCode = Humans.Constants.AnimalProtocolProcessType.Amendment;
					processName = Humans.Constants.AnimalProtocolProcessShortType.Amendment;
				}
				else if (this.Type == Humans.Constants.AnimalProtocolProcessType.Deficiency)
				{
					typeRefCode = Humans.Constants.AnimalProtocolProcessType.Deficiency;
					processName = Humans.Constants.AnimalProtocolProcessShortType.Deficiency;
				}
				else if (this.Type == Humans.Constants.AnimalProtocolProcessType.AnnualReview)
				{
					typeRefCode = Humans.Constants.AnimalProtocolProcessType.AnnualReview;
					processName = Humans.Constants.AnimalProtocolProcessShortType.AnnualReview;
				}
				else if (this.Type == Humans.Constants.AnimalProtocolProcessType.TriennialReview)
				{
					typeRefCode = Humans.Constants.AnimalProtocolProcessType.TriennialReview;
					processName = Humans.Constants.AnimalProtocolProcessShortType.TriennialReview;
				}
				else
				{
					throw new Exception("Unrecognized Process Type");
				}

				// Figure out the count of this type of process, and add it into the name
				int processCount = Protocol.GetProcessCount(typeRefCode, this.ProtocolId, insightConnectionString);

				int rexProcessCount = 0;
				try
				{
					object result = Utility.DataAccess.ExecuteScalar(Utility.DataAccess.GetConnectionString("Rex"),
						"GetMaxAnimalsProcessNumber",
						Utility.DataAccess.BuildSqlParameterArray(
						"@nAnimalProtID", SqlDbType.Int, rexProtId,
						"@sProcessType", SqlDbType.VarChar, typeRefCode));

					if (result != null)
						rexProcessCount = (int)result;
				}
				catch
				{
					throw;
				}
				if (rexProcessCount > processCount)
				{
					processCount = rexProcessCount;
				}

				++processCount;

				this.Name = String.Format("{0}{1}", processName, processCount.ToString());
			}

		}
		
		/// <summary>
		/// Broken-out method called within Submit, only if the Parent protocol's module type is Humans
		/// </summary>
		/// <param name="cachePolicy">cache policy</param>
		/// <param name="insightConnectionString">insight conn string</param>
		/// <param name="rexConnectionString">rex conn string</param>
		/// <param name="executingAssemblyPath">local executing path</param>
		/// <param name="rexParameters">RexParams object instance</param>
		/// <param name="submissionScriptType">type of the Submission</param>
		/// <param name="currProtocol">the current protocol- this processes' parent</param>
		/// <param name="IsRelocked">flag passed into Submit, passed thru here</param>
		private void SubmitHumansProcess(ICachePolicy cachePolicy, string insightConnectionString, string rexConnectionString,
					string executingAssemblyPath, RexParams rexParameters, string submissionScriptType, Protocol currProtocol, bool IsRelocked)
		{
			ArrayList scripts = ScriptEngine.Script.GetScriptsByType(insightConnectionString,
				submissionScriptType, cachePolicy);

			ScriptEngine.Script submissionScript = null;

			if (scripts.Count > 0)
				submissionScript = (ScriptEngine.Script)scripts[0];

			if (submissionScript != null)
			{
				using (ScriptEngine.ScriptEngineHost scriptHost =
				   new PHSRAG.Insight21.ScriptEngine.ScriptEngineHost(
						 ScriptEngine.Constants.RootMoniker.SubmissionScriptMoniker,
						 ScriptEngine.Constants.RootNamespaces.SubmissionScript,
						 true))
				{
					ArrayList refs = ScriptEngine.ScriptReference.GetAllScriptReferences(
					   insightConnectionString);

					for (int i = 0; i < refs.Count; ++i)
					{
						ScriptEngine.ScriptReference reference = (ScriptEngine.ScriptReference)refs[i];
						scriptHost.AddDLLReference(string.Format("{0}\\{1}", executingAssemblyPath, reference.Name));
						//scriptHost.AddDLLReference ( reference.Name );	
					}

					// add the connection string
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ConnectionString,
					   insightConnectionString);

					// add the Process
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolProcss,
					   this);

					ProtocolVersion currentVersion = GetLatestProtocolVersion(insightConnectionString,
					   false, cachePolicy) as ProtocolVersion;
					if (currentVersion == null)
					{
						throw new Exception("No protocol version found");
					}
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.ProtocolVersion, currentVersion);


					// add the RexParams
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.RexParams, rexParameters);

					// add the caching policy
					scriptHost.AddIntrinsicObject(ScriptEngine.Constants.Instrinsics.CachePolicy, cachePolicy);

					// compile and run the script.
					if (scriptHost.Compile(submissionScript))
						scriptHost.RunScript(submissionScript,
						   ScriptEngine.Constants.AssemblyType.SubmissionScript,
						   ScriptEngine.Constants.MethodsToRun.Main);
				}
			}


			//Protocol currProtocol = new Protocol ( cachePolicy );
			//currProtocol.Load ( insightConnectionString, this.ProtocolId );

			// look it up to see if
			// what we have is the current attachmentTitle # (in case it's
			// been cloned in Rex bc of Amendment or Correction)

			currProtocol.RexProtocolId = GetCurrentRexProtocolId(
											rexConnectionString,
											null,
											currProtocol.ProtocolNumber,
											Constants.ModuleType.Humans);
			currProtocol.Save(insightConnectionString);

			int rexProtId = currProtocol.RexProtocolId;
			SqlConnection rexConn = new SqlConnection(rexConnectionString);
			rexConn.Open();
			SqlTransaction rexTrans = rexConn.BeginTransaction();

			SqlConnection insightConn = new SqlConnection(insightConnectionString);
			insightConn.Open();
			SqlTransaction insightTrans = insightConn.BeginTransaction();

			// determine the appropriate type of Process here and pass it down.
			string RexIRBStatusType = string.Empty;
			switch (Type)
			{
				case Humans.Constants.ProtocolProcessType.Amendment:
					RexIRBStatusType = Humans.Constants.RexIRBStatusType.Amendment;
					break;
				case Humans.Constants.ProtocolProcessType.AdverseEvent:
					RexIRBStatusType = Humans.Constants.RexIRBStatusType.AdverseEvent;
					break;
				case Humans.Constants.ProtocolProcessType.ContinuingReview:
					RexIRBStatusType = Humans.Constants.RexIRBStatusType.ContinuingReview;
					break;
				case Humans.Constants.ProtocolProcessType.OtherEvent:
					RexIRBStatusType = Humans.Constants.RexIRBStatusType.OtherEvent;
					break;
				default:
					throw new Exception(string.Format("Unknown Process Type: {0}", Type));
			}

			try
			{
				// Go get the correct protocol process number (ex. AME2) here, immediately before moving it over to Rex.
				if (this.Type != ProtocolProcessType.Application.ToString() && !IsRelocked && this.Name.Contains("InProg"))
				{
					string typeRefCode = string.Empty;
					string rexTabTypeName = string.Empty;
					string processName = string.Empty;

					if (this.Type == Humans.Constants.ProtocolProcessType.Amendment)
					{
						typeRefCode = Humans.Constants.ProtocolProcessType.Amendment;
						rexTabTypeName = Humans.Constants.RexIRBStatusType.Amendment;
						processName = Humans.Constants.ProtocolProcessShortType.Amendment;
					}
					else if (this.Type == Humans.Constants.ProtocolProcessType.AdverseEvent)
					{
						typeRefCode = Humans.Constants.ProtocolProcessType.AdverseEvent;
						rexTabTypeName = Humans.Constants.RexIRBStatusType.AdverseEvent;
						processName = Humans.Constants.ProtocolProcessShortType.AdverseEvent;
					}
					else if (this.Type == Humans.Constants.ProtocolProcessType.ContinuingReview)
					{
						typeRefCode = Humans.Constants.ProtocolProcessType.ContinuingReview;
						rexTabTypeName = Humans.Constants.RexIRBStatusType.ContinuingReview;
						processName = Humans.Constants.ProtocolProcessShortType.ContinuingReview;
					}
					else if (this.Type == Humans.Constants.ProtocolProcessType.OtherEvent)
					{
						typeRefCode = Humans.Constants.ProtocolProcessType.OtherEvent;
						rexTabTypeName = Humans.Constants.RexIRBStatusType.OtherEvent;
						processName = Humans.Constants.ProtocolProcessShortType.OtherEvent;
					}
					else
					{
						throw new Exception("Unrecognized Process Type");
					}

					// Figure out the count of this type of process, and add it into the name
					int processCount = Protocol.GetProcessCount(typeRefCode, this.ProtocolId, insightConnectionString);

					int rexProcessCount = 0;
					try
					{
						object result = Utility.DataAccess.ExecuteScalar(Utility.DataAccess.GetConnectionString("Rex"),
							"GetMaxProcessNumber",
							Utility.DataAccess.BuildSqlParameterArray(
							"@nIRBProtocolId", SqlDbType.Int, rexProtId,
							"@appType", SqlDbType.VarChar, rexTabTypeName));

						if (result != null)
							rexProcessCount = (int)result;
					}
					catch
					{
						throw;
					}
					if (rexProcessCount > processCount)
					{
						processCount = rexProcessCount;
					}

					++processCount;

					this.Name = String.Format("{0}{1}", processName, processCount.ToString());

				}

				// call method and get the latest 'stuff' to pass in here.
				DataSet results = this.GetLatestHumansRexProcessData(currProtocol.ProtocolNumber, rexTrans, this.RexTabType);

				DateTime dateReceived = DateTime.Now;

                if (results.Tables[0].Rows.Count > 0)
                {
                    object o = results.Tables[0].Rows[0]["dtReceived"];
                    dateReceived = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;

                    o = results.Tables[0].Rows[0]["nStatusId"];
                    if ((int)o != 0)
                        RexIRBStatusId = (int)o;

                    o = results.Tables[0].Rows[0]["nIRBProtocolId"];
                    if ((int)o > 0 && (int)o != rexProtId)
                        rexProtId = (int)o;
                }

				// spIRBStatusUpdate
				int irbStatusId = Convert.ToInt32(Utility.DataAccess.ExecuteScalar(rexConn, rexTrans,
					"spIRBStatusUpdate",
					Utility.DataAccess.BuildSqlParameterArray(
					"@nWorkStatusID", SqlDbType.Int, RexIRBStatusId,
					"@nTabTypeID", SqlDbType.Int, ProcessCount,
					"@sTabType", SqlDbType.VarChar, RexIRBStatusType,
					"@nIRBProtocolId", SqlDbType.Int, rexProtId,
					"@sAmeSponsorNumber", SqlDbType.VarChar, rexParameters.SponsorAMENumber,
					"@sAdvPatientID", SqlDbType.VarChar, rexParameters.SubjectNumber,
					"@sAEReportType", SqlDbType.VarChar, rexParameters.AEReportType,
					"@sAEExpected", SqlDbType.Char, rexParameters.Expected,
					"@sAEGradeSeverity", SqlDbType.Char, rexParameters.AEGradeSeverity,
					"@sAERelated", SqlDbType.Char, rexParameters.AERelated,
					"@dtAdvEventOccurred", SqlDbType.DateTime, (rexParameters.AEDateOccurred == DateTime.MinValue) ? (object)DBNull.Value : (object)rexParameters.AEDateOccurred,
					"@dtReceived", SqlDbType.DateTime, dateReceived,
					"@dtAnnClosed", SqlDbType.DateTime, (rexParameters.CRDateClosed == DateTime.MinValue) ? (object)DBNull.Value : (object)rexParameters.CRDateClosed,
					"@sAnnProjectStatus", SqlDbType.VarChar, (rexParameters.CRProjectStatus == string.Empty) ? (object)DBNull.Value : (object)rexParameters.CRProjectStatus,
					"@nAnnSpecimenstoDate", SqlDbType.Int, (rexParameters.CRSpecimensToDate == 0) ? (object)DBNull.Value : (object)rexParameters.CRSpecimensToDate,
					"@nAnnRecordstoDate", SqlDbType.Int, (rexParameters.CRRecordsToDate == 0) ? (object)DBNull.Value : (object)rexParameters.CRRecordsToDate,
					"@sOtherEventType", SqlDbType.VarChar, (rexParameters.OEEventType == string.Empty) ? (object)DBNull.Value : (object)rexParameters.OEEventType,
					"@sAmeVioDescription", SqlDbType.VarChar, (rexParameters.OEDescription == string.Empty) ? (object)DBNull.Value : (object)rexParameters.OEDescription)));

				/// SET THE REX IRBStatusID on it.
				if (irbStatusId != 0)
					this.RexIRBStatusId = irbStatusId;

				// now set the ProcessID on the IRBStatus record, rather than passing it 
				// in as a new parameter to Rex, which would require MAJOR VB code changes to 
				// Rex when cloning protocols. 
				//UpdateIRBStatusForProcess
				Utility.DataAccess.ExecuteNonQuery(rexConn, rexTrans,
					"UpdateIRBStatusForProcess",
					Utility.DataAccess.BuildSqlParameterArray(
					"@tblIRBStatusId", SqlDbType.Int, RexIRBStatusId,
					"@processId", SqlDbType.Int, Id));


                //// Now set the flag for the process that it has been submitted to Rex.
                //Utility.DataAccess.ExecuteNonQuery(insightConn, insightTrans,
                //    "UpdateMoveToRexSatusForProcess",
                //    Utility.DataAccess.BuildSqlParameterArray(
                //    "@processId", SqlDbType.Int, Id));

				this.Save(insightTrans);

				rexTrans.Commit();
				insightTrans.Commit();
			}
			catch
			{
				rexTrans.Rollback();
				insightTrans.Rollback();
				throw;
			}
			finally
			{
				if (rexConn.State != ConnectionState.Closed)
					rexConn.Close();
				if (insightConn.State != ConnectionState.Closed)
					insightConn.Close();
			}
		}

		/// <summary>
		/// Updates the Protocol record in REX with PI information
		/// </summary>
		/// <param name="insightConnectionString">string containing
		/// info to connect to Insight db</param>
		/// <param name="rexConnectionString">string containing
		/// info to connect to REX db</param>
		/// <param name="protocol">protocol to udpate</param>
		/// <param name="rexTransaction">transaction to use to perform
		/// the update</param>
		private void UpdatePIInREX(string insightConnectionString,
			string rexConnectionString, Protocol protocol,
			SqlTransaction rexTransaction, int rexRecomId)
		{
			CDS.Person PI = new CDS.Person(CachePolicy);
			PI.Load(insightConnectionString, protocol.PIPersonId);

			// check the PI has a Recom ID since Rex requires it.
			if (PI != null && PI.RexRecomId == 0)
				PI.CreateRecomRecord(insightConnectionString, rexConnectionString);

			CDS.Organization PIOrg = new PHSRAG.Insight21.CDS.Organization(CachePolicy);
			PIOrg.Load(insightConnectionString, PI.OrganizationId);
			// create Institution, Department and Unit Orgs for the PI's Org.
			Organization PIOrgInstitution = new PHSRAG.Insight21.CDS.Organization(CachePolicy);
			PIOrgInstitution.Load(insightConnectionString, PIOrg.InstitutionId);
			Organization PIOrgDept = new PHSRAG.Insight21.CDS.Organization(CachePolicy);
			PIOrgDept.Load(insightConnectionString, PIOrg.DepartmentId);
			Organization PIOrgUnit = new PHSRAG.Insight21.CDS.Organization(CachePolicy);
			PIOrgUnit.Load(insightConnectionString, PIOrg.UnitId);

			string unitName =
				(PIOrgUnit == null || PIOrgUnit.Name == null ||
				PIOrgUnit.Name == string.Empty) ? "(None)" :
				String.Format("{0} {1}", PIOrgUnit.Name, PIOrgUnit.ChiefCode);

			Utility.DataAccess.ExecuteScalar(
				rexTransaction.Connection,
				rexTransaction,
				"spIRBPIInfoUpdate",
				Utility.DataAccess.BuildSqlParameterArray(
				"@sFolderNumber", SqlDbType.VarChar, protocol.ProtocolNumber,
				"@nPIID", SqlDbType.Int, rexRecomId,
				"@sPIInstitution", SqlDbType.VarChar,
					String.Format("{0} {1}", PIOrgInstitution.Name, PIOrgInstitution.ChiefCode),
				"@sPIDept", SqlDbType.VarChar,
					String.Format("{0} {1}", PIOrgDept.Name, PIOrgDept.ChiefCode),
				"@sPIUnit", SqlDbType.VarChar, unitName));
		}

		/// <summary>Checks whether or not the required questions in a questionnaire is answered </summary>
		/// <param name="qI">Questionnaire Item</param>
		/// <param name="parentValue">Parent value of the questionnaire Item</param>
		/// <param name="questionnaireAnswer">Questionnaire answer</param>
		/// <param name="qV">Questionnaire version corresponding to the answer</param>
		public void checkRequiredItems(Forms.QuestionnaireItem qI, string parentValue, Forms.QuestionnaireAnswer questionnaireAnswer, Forms.QuestionnaireVersion qV)
		{
			ArrayList itemAnswers = questionnaireAnswer.GetAnswers((string)qI.Name);

			if (0 == itemAnswers.Count && qI.Required)
			{
				SaveLogItem(qI, questionnaireAnswer);
			}
			else
			{
				foreach (Forms.Answer itemAnswer in itemAnswers)
				{
					CheckRequiredItems(qI, itemAnswer, questionnaireAnswer, qV);
				}
			}
		}
		/// <summary>
		/// A recursive function to check whether or not the required questions in a questionnaire are answered. (For non-top-level questions)
		/// </summary>
		/// <param name="qI">Question whose child questions have to be verified</param>
		/// <param name="qIAnswer">Question's Answer</param>
		/// <param name="questionnaireAnswer">QuestionnaireAnswer</param>
		/// <param name="qV">Questionnaire version corresponding to the answer</param>
		private void CheckRequiredItems(Forms.QuestionnaireItem qI, Forms.Answer qIAnswer,
			Forms.QuestionnaireAnswer questionnaireAnswer, Forms.QuestionnaireVersion qV)
		{
			//scan thru all the childquestions whose parentvalue field matches the current answer
			//or if the current question is a multiselect or dropdownmultiselect question
			foreach (Forms.QuestionnaireItem child in qV.GetItems(qI.Name).Values)
			{
				//if child is required and either its parentvalue condition is met or its parent is any of the multiselect questions
				//then check if the child is answered
				if (child.Required && (qIAnswer.Value == child.ParentValue 
											|| qI.Type == Forms.QuestionnaireItem.MultiSelectItemType 
											|| qI.Type == Forms.QuestionnaireItem.DropDownMultiSelectItemType
											|| qI.Type == Forms.QuestionnaireItem.CustomValueSelectorItemType))
				{
					bool itemAnswered = false;
					if (qIAnswer.ChildAnswers != null)
					{
						foreach (Forms.Answer childAnswer in qIAnswer.ChildAnswers)
						{
							if (childAnswer.Name == child.Name)
							{
								itemAnswered = true;
								break;
							}
						}
					}
					if (!itemAnswered)
					{
						SaveLogItem(child, questionnaireAnswer);
					}
				}
				if (qIAnswer.ChildAnswers != null)
				{
					//check required items for each child and foreach of its answers.
					foreach (Forms.Answer childAnswer in qIAnswer.ChildAnswers)
					{
						if (childAnswer.Name == child.Name)
						{
							CheckRequiredItems(child, childAnswer, questionnaireAnswer, qV);
						}
					}
				}
			}
		}

		/// <summary>
		/// Get the latest Rex ProtocolId for the Parent ProtocolNumber in Insight.
		/// Rex transaction is readily available in the caller function and hence taking it as a parameter.
		/// </summary>       
		/// <param name="rexConnectionString">rex Connection string to be used in case a rex transaction is unavailable</param>
		/// <param name="rexTrans">rex transaction</param>
		/// <param name="insightParentProtocolNumber">Parent protocol number for the  process in rex</param>
		/// <returns>current Rex ProtocolId</returns>
		public int GetCurrentRexProtocolId(string rexConnectiontring, SqlTransaction rexTrans, string insightParentProtocolNumber, string moduleType)
		{
			try
			{
				if (null != rexTrans && null != rexTrans.Connection)
				{

					return Convert.ToInt32(Utility.DataAccess.ExecuteScalar(rexTrans.Connection, rexTrans,
						(moduleType == Constants.ModuleType.Humans) ? "spIRBRetrieveCurrentProtocolId" : "spAnimalsRetrieveCurrentProtocolId",
									Utility.DataAccess.BuildSqlParameterArray(
									"@sFolderNumber", SqlDbType.VarChar, insightParentProtocolNumber)));

				}
				else
				{
					if (!string.IsNullOrEmpty(rexConnectiontring))
					{
						return Convert.ToInt32(Utility.DataAccess.ExecuteScalar(rexConnectiontring,
						(moduleType == Constants.ModuleType.Humans) ? "spIRBRetrieveCurrentProtocolId" : "spAnimalsRetrieveCurrentProtocolId",
									Utility.DataAccess.BuildSqlParameterArray(
									"@sFolderNumber", SqlDbType.VarChar, insightParentProtocolNumber)));
					}
					else
					{
						throw new Exception("Either rex connection string or transaction is required to get the currentRexProtocolId");
					}

				}
			}
			catch (Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed, when executing the GetCurrentRexProtocolId()", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// Get the latest Rex ProtocolId for the Parent ProtocolNumber in Insight.
		/// Rex transaction is readily available in the caller function and hence taking it as a parameter.
		/// </summary>       
		/// <param name="rexTrans">rex connection string to be used in case the rex connection is null</param>
		/// <param name="rexTrans">rex transaction</param>
		/// <param name="insightParentProtocolNumber">Parent protocol number for the  process in rex</param>
		/// <returns>current Rex ProtocolId</returns>
		public int GetCurentRexDocumentNumber(string rexconnectionString, SqlTransaction rexTrans, string insightParentProtocolNumber, string moduleType)
		{
			try
			{
				if (null != rexTrans && null != rexTrans.Connection)
				{
					return Convert.ToInt32(Utility.DataAccess.ExecuteScalar(rexTrans.Connection, rexTrans,
						 (moduleType == Constants.ModuleType.Humans) ? "spIRBRetrieveCurrentDocumentNumber" : "spAnimalsRetrieveCurrentDocumentNumber",
									 Utility.DataAccess.BuildSqlParameterArray(
									 "@sFolderNumber", SqlDbType.VarChar, insightParentProtocolNumber)));
				}
				else
				{
					if (!string.IsNullOrEmpty(rexconnectionString))
					{
						return Convert.ToInt32(Utility.DataAccess.ExecuteScalar(rexconnectionString,
						(moduleType == Constants.ModuleType.Humans) ? "spIRBRetrieveCurrentDocumentNumber" : "spAnimalsRetrieveCurrentDocumentNumber",
									Utility.DataAccess.BuildSqlParameterArray(
									"@sFolderNumber", SqlDbType.VarChar, insightParentProtocolNumber)));
					}
					else
					{
						throw new Exception("Either rex connection string or transaction is required to get the CurrentDocumentNumber");
					}
				}
			}
			catch (Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed, when executing the GetCurrentRexDocumentNumber()", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// Load the properties with the datarow 
		/// </summary>
		/// <param name="row">datarow </param>
		private void PopulateDataMembers(DataRow row)
		{
			Id = (int)row[ColumnId];
			object o = (int)row[ColumnProtocolId];
			protocolId = (o == DBNull.Value) ? 0 : (int)row[ColumnProtocolId];
			o = row[ColumnName];
			name = (o == DBNull.Value) ? string.Empty : (string)row[ColumnName];
			o = row[ColumnType];
			type = (o == DBNull.Value) ? string.Empty : (string)row[ColumnType];
			o = row[ColumnStatus];
			status = (o == DBNull.Value) ? string.Empty : (string)row[ColumnStatus];
			locked = (bool)row[ColumnLocked];
			o = row[ColumnLastLockedVersion];
			lastLockedVersion = (o == DBNull.Value) ? 0 : (int)o;
			o = row[ColumnReceivedDate];
			receivedDate = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			o = row[ColumnApprovalDate];
			approvalDate = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			o = row[ColumnExpirationDate];
			expirationDate = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			o = row[ColumnCreateDate];
			createDate = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			o = row[ColumnPrimaryReviewerId];
			primaryReviewerId = (o == DBNull.Value) ? 0 : (int)o;
			o = row[ColumnSecondaryReviewerId];
			secondaryReviewerId = (o == DBNull.Value) ? 0 : (int)o;
			o = row[ColumnSubmitterId];
			submitterId = (o == DBNull.Value) ? 0 : (int)o;
			o = row[ColumnLastModifiedByUserId];
			lastModifiedByUserId = (o == DBNull.Value) ? 0 : (int)o;
			lastModifiedDate = (DateTime)row[ColumnLastModifiedDate];
			o = row[ColumnSubmittedDate];
			submittedDate = (o == DBNull.Value) ? DateTime.MinValue : (DateTime)o;
			showStaff = (bool)row[ColumnShowStaff];
			showAttachments = (bool)row[ColumnShowAttachments];
			o = row[ColumnRexIRBStatusId];
			rexIRBStatusId = (o == DBNull.Value) ? 0 : (int)o;
			beenSubmitted = (bool)row[ColumnBeenSubmitted];
			hasBeenLocked = (bool)row[ColumnHasBeenLocked];
			resubmission = (bool)row[ColumnResubmission];
            o = row[ColumnMovedToRex];
            movedToRex = (o == DBNull.Value) ? 0 : (int)o;            
		}

		/// <summary>
		/// Get the unlocked protocol version ID for the protocol process ID
		/// </summary>
		/// <returns>protocol version</returns>
		public int GetProtocolVersionId()
		{
			try
			{
				int protocolVersionId = (int)Utility.DataAccess.ExecuteScalar(DataAccess.GetConnectionString(), "GetProtocolLatestVersion", Utility.DataAccess.BuildSqlParameterArray(
					"@protocolProcessId", SqlDbType.Int, Id //19// Testing Purpose
					));

				return protocolVersionId;
			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed to get the Protocol Version Id,error occurred at GetProtocolVersionId ", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}
		/// <summary>
		/// Removes all the logItem tied with the Protocol Process Id from the database
		/// </summary>
		public void RemoveLogItems()
		{
			try
			{
				Utility.DataAccess.ExecuteNonQuery(DataAccess.GetConnectionString(), "RemoveLogItemsForProcess", Utility.DataAccess.BuildSqlParameterArray(
					"@protocolProcessId", SqlDbType.Int, Id));
			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed to remove log Item , error occurred at RemovelogItems()", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// Get the Latest verison of the protocol
		/// </summary>
		/// <returns>Protocol version object</returns>
		public ProtocolVersion GetLatestProtocolVersion(bool forModification, ICachePolicy cachePolicy)
		{
			return GetLatestProtocolVersion(Utility.DataAccess.ConnectionString, forModification, cachePolicy);
		}


		/// <summary>
		/// Get the Latest verison of the protocol
		/// </summary>
		/// <returns>Protocol version object</returns>
		public ProtocolVersion GetLatestProtocolVersion(string connectionString, bool forModification, ICachePolicy cachePolicy)
		{
			ProtocolVersion protocolVersion = null;

			try
			{
				DataTable protocolVersionDataTable = Utility.DataAccess.GetDataTable(connectionString,
					"GetProtocolLatestVersion",
					Utility.DataAccess.BuildSqlParameterArray(
					"@protocolProcessId", SqlDbType.Int, Id));

				if (protocolVersionDataTable != null && protocolVersionDataTable.Rows.Count != 0)
				{
					DataRow row = protocolVersionDataTable.Rows[0];
					protocolVersion = new ProtocolVersion(cachePolicy, row);

					if (true == forModification)
					{
						if (lastLockedVersion >= protocolVersion.Version)
						{
							protocolVersion = protocolVersion.Clone();
						}
					}
				}
				return protocolVersion;
			}

			catch (Exception ex)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed to get latest protocol Version,error occurred at GetLatestProtocolVersion()", ex, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}

		/// <summary>
		/// Verify the answer availability for the given Questionnaire Item
		/// </summary>
		/// <param name="questionnaireItemobject">questionnaire Item Collection to be verified</param>
		/// <param name="questionnaireVersion">version of the Questionnaire</param>

		private void VerifyAnswer(Forms.QuestionnaireItem questionnaireItem, Forms.QuestionnaireAnswer questionnaireAnswer)//,Forms.QuestionnaireVersion questionnaireVersion)
		{
			try
			{
				ArrayList itemAnswers = questionnaireAnswer.GetAnswers((string)questionnaireItem.Name);

				//				if (questionnaireItem.ValidationMessage!=string.Empty && 0==itemAnswers.Count)
				if (0 == itemAnswers.Count)
				{
					SaveLogItem(questionnaireItem, questionnaireAnswer);
				}
			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog(" Failed to validate the answer,error occurred at VerifyAnswer()", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
		}


		/// <summary>
		/// Save the Log Items corresponding to the required questionnaireItem to the database
		/// </summary>
		/// <param name="questionnaireItem">Questionnaire Item object</param>
		private void SaveLogItem(Forms.QuestionnaireItem questionnaireItem, Forms.QuestionnaireAnswer questionnaireAnswer)
		{

			try
			{
				LogItem logItem = new LogItem(CachePolicy);

				logItem.Category = string.Empty;//(string)questionnaireItem.ValidationCategory;
				logItem.Type = questionnaireAnswer.Name;
				logItem.QuestionnaireVersionId = (int)questionnaireItem.VersionId;
				logItem.QuestionnaireAnswerId = questionnaireAnswer.Id;
				logItem.Completed = false;
				logItem.Description = (questionnaireItem.ValidationMessage == string.Empty) ? (string)questionnaireItem.Name : (string)questionnaireItem.ValidationMessage;
				logItem.QuestionName = (string)questionnaireItem.Name;
				logItem.Answer = (string)questionnaireItem.ParentValue;

				SaveLogItem(logItem);

			}
			catch (Exception e)
			{
				Utility.ExceptionReport.WriteToEventLog("Failed to save the LogItem,error occurred at SaveLogItem())", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}

		}

		/// <summary>
		/// Save the Log Item to the database
		/// </summary>
		/// <param name="logItem">log item object to be saved</param>
		public void SaveLogItem(LogItem logItem)
		{
			SqlConnection insightConn = null;
			SqlTransaction insightTrans = null;

			try
			{
				insightConn = new SqlConnection(DataAccess.ConnectionString);
				insightConn.Open();
				insightTrans = insightConn.BeginTransaction();

				logItem.Save(insightTrans);

				Utility.DataAccess.ExecuteScalar(insightTrans.Connection, insightTrans, "SaveProtocolProcessLogItemMap",
					Utility.DataAccess.BuildSqlParameterArray(
					"@protocolProcessId", SqlDbType.Int, Id
					, "@logItemId", SqlDbType.Int, logItem.Id
					));

				insightTrans.Commit();

			}
			catch (Exception e)
			{
				// rollback the transaction if it exists.
				if (insightTrans != null)
				{
					insightTrans.Rollback();
				}
				Utility.ExceptionReport.WriteToEventLog("Failed to save the LogItem, error occurred at SaveLogItem())", e, true, Utility.ExceptionReport.ReportType.Error);
				throw;
			}
			finally
			{
				if (insightConn.State != ConnectionState.Closed)
					insightConn.Close();
			}

		}

		/// <summary>
		/// GetProtocolProcess returns the correct type of class
		/// </summary>
		/// <param name="connectionString"></param>
		/// <param name="processId"></param>
		/// <param name="CachePolicy"></param>
		/// <returns></returns>
		public static ProtocolProcess GetProtocolProcess(string connectionString, int processId, ICachePolicy cachePolicy, DataRow dataRow)
		{
			if (dataRow == null)
			{
				try
				{
					DataTable protocolProcessDataTable = Utility.DataAccess.GetDataTable(connectionString, "GetProtocolProcess",
						Utility.DataAccess.BuildSqlParameterArray("@id", SqlDbType.Int, processId));
					dataRow = protocolProcessDataTable.Rows[0];
					// set the properties.
					//PopulateDataMembers ( dataRow );
				}
				catch (Exception e)
				{
					Utility.ExceptionReport.WriteToEventLog("ProtocolProcess.GetProtocolProcess", e, true, Utility.ExceptionReport.ReportType.Error);
					throw;
				}
			}

			string processType = (string)dataRow["Type"];

			switch (processType)
			{
				case Constants.ProtocolProcessType.InitialReview:
					Application newApp = new Application(cachePolicy, dataRow);
					return newApp;
				case Constants.ProtocolProcessType.Amendment:
					Amendment newAmend = new Amendment(cachePolicy, dataRow);
					return newAmend;
				case Constants.ProtocolProcessType.AdverseEvent:
					AdverseEvent newAE = new AdverseEvent(cachePolicy, dataRow);
					return newAE;
				case Constants.ProtocolProcessType.ContinuingReview:
					ContinuingReview newCR = new ContinuingReview(cachePolicy, dataRow);
					return newCR;
				case Constants.ProtocolProcessType.OtherEvent:
					OtherEvent newOE = new OtherEvent(cachePolicy, dataRow);
					return newOE;
				case Constants.AnimalProtocolProcessType.InitialReview:
					Application newAnimalsApp = new Application(cachePolicy, dataRow);
					newAnimalsApp.Type = Constants.AnimalProtocolProcessType.InitialReview;
					return newAnimalsApp;
				case Constants.AnimalProtocolProcessType.Amendment:
					Amendment newAnimalsAmend = new Amendment(cachePolicy, dataRow);
					newAnimalsAmend.Type = Constants.AnimalProtocolProcessType.Amendment;
					return newAnimalsAmend;
				case Constants.AnimalProtocolProcessType.Deficiency:
					AdverseEvent newAnimalsAE = new AdverseEvent(cachePolicy, dataRow);
					newAnimalsAE.Type = Constants.AnimalProtocolProcessType.Deficiency;
					return newAnimalsAE;
				case Constants.AnimalProtocolProcessType.AnnualReview:
					ContinuingReview newAnimalsAR = new ContinuingReview(cachePolicy, dataRow);
					newAnimalsAR.Type = Constants.AnimalProtocolProcessType.AnnualReview;
					return newAnimalsAR;
				case Constants.AnimalProtocolProcessType.TriennialReview:
					ContinuingReview newAnimalsTR = new ContinuingReview(cachePolicy, dataRow);
					newAnimalsTR.Type = Constants.AnimalProtocolProcessType.TriennialReview;
					return newAnimalsTR;
				default: throw new Exception("Unrecognized Process Type");
			}
		}
		#endregion
	    
    }

	#region Enum
	/// <summary>
	/// Enum for Protocol process type 
	/// </summary>
	public enum ProtocolProcessType
	{
		Application,
		Amendment,
		ContinuingReview,
		AdverseEvent,
		OtherEvent,
		AnimalsApplication,
		AnimalsAnnualReview,
		AnimalsDeficiency,
		AnimalsTriennialReview,
		AnimalsAmendment
	}
	#endregion

}
